package com.aabte.lota.auth.auth.shiro.configure;

import com.aabte.lota.auth.auth.shiro.JwtAuthenticationFilter;
import com.aabte.lota.auth.auth.token.JWTTokenRefreshFilter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.Filter;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.Ordered;
import org.springframework.web.filter.DelegatingFilterProxy;

/**
 * @author Daniel
 * @version 1.0
 * @date 2020/4/8
 */
@Configuration
@ConditionalOnProperty(name = "shiro.enabled", matchIfMissing = true)
public class ShiroFilterConfig {

  @Bean
  public JWTTokenRefreshFilter tokenRefreshFilter() {
    return new JWTTokenRefreshFilter();
  }

  @Bean
  public FilterRegistrationBean<Filter> tokenRefreshFilterRegistrationBean() {
    FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>();
    filterRegistrationBean.setFilter(tokenRefreshFilter());
    filterRegistrationBean.setOrder(Ordered.LOWEST_PRECEDENCE);
    return filterRegistrationBean;
  }

  @Bean
  @DependsOn("jwtTokenFilter")
  public FilterRegistrationBean<Filter> delegatingFilterProxy() {
    DelegatingFilterProxy proxy = new DelegatingFilterProxy();
    proxy.setTargetFilterLifecycle(true);
    proxy.setTargetBeanName("jwtTokenFilter");

    FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>();
    filterRegistrationBean.setFilter(proxy);
    filterRegistrationBean.setOrder(Ordered.LOWEST_PRECEDENCE - 1);
    return filterRegistrationBean;
  }

  @Bean(name = "jwtTokenFilter")
  public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
    ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();

    filterFactoryBean.setSecurityManager(securityManager);
    filterFactoryBean.setFilterChainDefinitionMap(shiroFilterChainDefinition().getFilterChainMap());

    Map<String, Filter> filterMap = new HashMap<>(1);
    filterMap.put("jwt", new JwtAuthenticationFilter());
    filterFactoryBean.setFilters(filterMap);
    return filterFactoryBean;
  }

  @Bean
  public ShiroFilterChainDefinition shiroFilterChainDefinition() {
    DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();

    // 接口文档允许匿名访问
    Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
    filterChainDefinitionMap.put("/", "anon");
    filterChainDefinitionMap.put("/csrf", "anon");
    filterChainDefinitionMap.put("/druid/**", "anon");
    filterChainDefinitionMap.put("/api-docs", "anon");
    filterChainDefinitionMap.put("/v2/api-docs", "anon");
    filterChainDefinitionMap.put("/swagger-ui.html", "anon");
    filterChainDefinitionMap.put("/webjars/**", "anon");
    filterChainDefinitionMap.put("/swagger-resources/**", "anon");

    filterChainDefinitionMap.put("/v1/login/token", "anon");
    filterChainDefinitionMap.put("/v1/user/register", "anon");
    filterChainDefinitionMap.put("/**", "jwt");
    chainDefinition.addPathDefinitions(filterChainDefinitionMap);

    return chainDefinition;
  }
}
